// Header Protection
#ifndef _SHADERMANAGER_H_
#define _SHADERMANAGER_H_

// Include Files
#include "Event\Event.h"

// Forward Declarations
class CShaderLoadEventArg;

// TODO: remove unneeded
typedef int CGbool;
typedef struct _CGcontext *CGcontext;
//typedef struct _CGprogram *CGprogram;
typedef struct _CGparameter *CGparameter;
//typedef struct _CGobj *CGobj;
//typedef struct _CGbuffer *CGbuffer;
typedef struct _CGeffect *CGeffect;
typedef struct _CGtechnique *CGtechnique;
typedef struct _CGpass *CGpass;
//typedef struct _CGstate *CGstate;
//typedef struct _CGstateassignment *CGstateassignment;
//typedef struct _CGannotation *CGannotation;
//typedef void *CGhandle;

struct TPassData
{
	CGpass pass;
	CGbool bCullFace;
};

/////////////////////////////////////////////////////////////////////////////////////
// This class maintains a list of all loaded shaders and uses an indexing system in 
//     order to let other classes reference it's shaders.
class CShaderManager : public ISingleton<CShaderManager>
{
	struct TShader
	{
		string_t    strName;
		CGeffect    effect;
		CGtechnique technique;
	};

public:     // methods

	// Initialize shader management.
	void Initialize();

	// Shut down shader management.
	void Shutdown();

	// Load a shader file, send a ShaderLoad event with the file data.
	// _strFilename : string_t - the name of the file to load
	void LoadShaderFile( string_t _strFilename );

	// Create an OpenGL shader from the ShaderLoad event argument.
	// _rArg : CShaderLoadEventArg const & - the event 
	//     argument to create a shader from
	void CreateShader( CShaderLoadEventArg &_rArg );

	// Retrieve the effect from a shader.
	// _strShader : string_t - the name of the shader to retrieve the effect from
	// return : CGeffect - the effect from the given shader
	CGeffect GetEffect( string_t _strShader );

	// Retrieve the technique from a shader.
	// _strShader : string_t - the name of the shader to retrieve the technique from
	// return : CGtechnique - the technique from the given shader
	CGtechnique GetTechnique( string_t _strShader );

	// Retrieve a parameter from a shader.
	// _strShader : string_t - the name of the shader to retrieve a parameter from
	// _strName:  string_t - the name of the parameter to get from the shader
	// return : CGparameter - the given parameter
	CGparameter GetParameter( string_t _strShader, string_t _strName );

	TPassData *GetPassData(CGpass _pass)
	{
		uint_t uIndex = 0;
		for( ; uIndex < m_lstPassData.GetSize(); ++uIndex )
		{
			if( m_lstPassData[uIndex].pass == _pass )
			{
				return &m_lstPassData[uIndex];
			}
		}

		// new pass data
		TPassData data;

		// default values
		data.pass      = _pass;
		data.bCullFace = CE_TRUE;

		// add the pass data to the list
		m_lstPassData.Append(data);
		return &m_lstPassData[uIndex];
	}

public:     // events

	// A shader has been loaded from a file and needs to be created.
	CEvent<CShaderLoadEventArg> ShaderLoad;

private:    // friend methods
	friend class ISingleton<CShaderManager>;

	CShaderManager() : m_Context(CE_NULL), m_lstShaders() { }
	~CShaderManager() { }

private:    // dummy definitions
	CShaderManager( CShaderManager const & );
	CShaderManager &operator =( CShaderManager const & );

private:    // data members
	CGcontext         m_Context;
	list_t<TShader>   m_lstShaders; // TODO: pointers
	list_t<TPassData> m_lstPassData; // TODO: pointers
};

/////////////////////////////////////////////////////////////////////////////////////
// This class is an event argument used to pass shader data loaded from a file to 
//     the renderer where it can be loaded into the rendering system.
class CShaderLoadEventArg : public CEventArg
{
public:     // accessors
	inline string_t const &GetName() const { return m_strName; }

public:     // methods

	// _strName : string_t - the name to use to reference this shader
	inline CShaderLoadEventArg( string_t _strName ) : 
	CEventArg(), m_strName(_strName)
	{ }

	inline ~CShaderLoadEventArg() { }

private:    // data
	string_t m_strName;

private:    // dummy definitions
	CShaderLoadEventArg( CShaderLoadEventArg const & );
	CShaderLoadEventArg &operator =( CShaderLoadEventArg const & );
};

/////////////////////////////////////////////////////////////////////////////////////
// Header Protection
#endif // _SHADERMANAGER_H_
